#pragma once
#include <assert.h>
#include "VCBase.h"

template <class T>
class CRefPtr
{
public:
    typedef T element_type;

    CRefPtr() : ptr_(NULL)
    {
    }

    CRefPtr(T* p) : ptr_(p)
    {
        if (ptr_)
            ptr_->AddRef();
    }

    CRefPtr(const CRefPtr<T>& r) : ptr_(r.ptr_)
    {
        if (ptr_)
            ptr_->AddRef();
    }

    template <typename U>
    CRefPtr(const CRefPtr<U>& r) : ptr_(r.get())
    {
        if (ptr_)
            ptr_->AddRef();
    }

    ~CRefPtr()
    {
        if (ptr_)
            ptr_->Release();
    }

    T* get() const
    {
        return ptr_;
    }

    operator T*() const
    {
        return ptr_;
    }

    T* operator->() const
    {
        assert(ptr_ != NULL);
        return ptr_;
    }

    CRefPtr<T>& operator=(T* p)
    {
        if (p)
            p->AddRef();
        T* old_ptr = ptr_;
        ptr_ = p;
        if (old_ptr)
            old_ptr->Release();
        return *this;
    }

    CRefPtr<T>& operator=(const CRefPtr<T>& r)
    {
        return *this = r.ptr_;
    }

    template <typename U>
    CRefPtr<T>& operator=(const CRefPtr<U>& r)
    {
        return *this = r.get();
    }

private:
    T* ptr_;
};

template <class T>
class CWeakPtr : IWeakVisitor
{
public:
    typedef T element_type;

    CWeakPtr() : ptr_(nullptr)
    {
    }

    ~CWeakPtr()
    {
        if (ptr_)
            ptr_->UnRegisterWeakVisitor(this);

    }

    explicit CWeakPtr(T* p) : ptr_(p)
    {
        if (ptr_)
            ptr_->RegisterWeakVisitor(this);
    }

    template <typename U>
    CWeakPtr(const CRefPtr<U>& p)
    {
        if (p)
            p->RegisterWeakVisitor(this);
        ptr_ = p;
    }

    CWeakPtr<T>& operator=(T* p)
    {
        T* old_ptr = ptr_;
        if (old_ptr)
            old_ptr->UnRegisterWeakVisitor(this);

        if (p)
            p->RegisterWeakVisitor(this);
        ptr_ = p;

        return *this;
    }

    CWeakPtr<T>& operator=(const CRefPtr<T>& r)
    {
        return *this = r.get();
    }

    template <typename U>
    CWeakPtr<T>& operator=(const CRefPtr<U>& r)
    {
        return *this = r.get();
    }

    CRefPtr<T> Lock() const
    {
        return ptr_;
    }

protected:
    CWeakPtr<T>& operator=(const CWeakPtr<T>& r);

    template <typename U>
    CWeakPtr<T>& operator=(const CWeakPtr<U>& r);

private:
    virtual void Destory()
    {
        ptr_ = nullptr;
    }

private:
    T* ptr_;
};


template<class T, class U>
CRefPtr<T> DynamicRefPointerCast(CRefPtr<U> const& r)
{
    (void) dynamic_cast<T*>(static_cast<U*>(0));

    typedef typename CRefPtr<T>::element_type E;

    E * p = dynamic_cast<E*>(r.get());
    return p ? CRefPtr<T>(p) : CRefPtr<T>();
}